﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;

namespace Marmat.Forms
{
    [Designer("Marmat.Forms.Design.TabControlDesigner")]
    [ToolboxItem(true)]
    public partial class TabControl : System.Windows.Forms.UserControl, ISupportInitialize, IControl
    {
        public TabControl()
        {
            this.ControlRemoved += TabControl_ControlRemoved;
            this.SetStyle(ControlStyles.ResizeRedraw, true); // 尺寸变化后绘制
            this.SetStyle(ControlStyles.Opaque, false); // 改善绘图质量
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); // 使控件支持透明色
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.Font = new Font("微软雅黑", 9.0f);
            this.ShowTabs = true;
            base.BackColor = this.m_BackColor;
        }

        private Dictionary<TabPage, Rectangle> dic = new Dictionary<TabPage, Rectangle>();
        private bool doubleBuffer = false;
        private TabPage mouse_tabPage;
        private TabPage designMode_SelectedTab;

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            this.dic.Clear();
            int left = this.Padding.X;
            int top = 6;
            var pen = new Pen(Color.FromArgb(238, 238, 238));
            if (this.SelectedTab is object)
            {
                pen.Color = this.SelectedTab.BorderColor;
            }

            e.Graphics.DrawLine(pen, left, base.Padding.Top - 1, this.Width - left, base.Padding.Top - 1);
            var imageList = this.ImageList;
            foreach (TabPage tabPage in this.TabPages)
            {
                if (tabPage.TabVisible || this.DesignMode)
                {
                    var size = TextRenderer.MeasureText(e.Graphics, tabPage.Text, this.Font, this.Size, TextFormatFlags.NoPadding);
                    var bounds = new Rectangle(left, top, size.Width, base.Padding.Top - top);
                    int imageIndex = -1;
                    if (imageList is object)
                    {
                        if (Equals(this.SelectedTab, tabPage) || Equals(this.mouse_tabPage, tabPage))
                        {
                            if (tabPage.FocusImageIndex >= 0)
                            {
                                imageIndex = tabPage.FocusImageIndex;
                            }
                            else if (!string.IsNullOrEmpty(tabPage.FocusImageKey))
                            {
                                imageIndex = imageList.Images.IndexOfKey(tabPage.FocusImageKey);
                            }
                        }
                        else if (tabPage.ImageIndex >= 0)
                        {
                            imageIndex = tabPage.ImageIndex;
                        }
                        else if (!string.IsNullOrEmpty(tabPage.ImageKey))
                        {
                            imageIndex = imageList.Images.IndexOfKey(tabPage.ImageKey);
                        }
                    }

                    if (imageIndex >= 0 && imageIndex < imageList.Images.Count - 1)
                    {
                        bounds = new Rectangle(bounds.X, bounds.Y, bounds.Width + 3 + this.ImageList.ImageSize.Width, Math.Max(bounds.Height, this.ImageList.ImageSize.Height));
                    }

                    this.dic[tabPage] = bounds;
                    pen = new Pen(Color.Gray, 2f);
                    if (Equals(this.SelectedTab, tabPage) && this.designMode_SelectedTab is null || Equals(this.designMode_SelectedTab, tabPage) || Equals(this.mouse_tabPage, tabPage))
                    {
                        pen.Color = Color.FromArgb(52, 143, 228);
                        e.Graphics.DrawLine(pen, bounds.X, bounds.Bottom - 1, bounds.Right, bounds.Bottom - 1);
                    }

                    if (imageIndex >= 0 && imageIndex < imageList.Images.Count - 1)
                    {
                        imageList.Draw(e.Graphics, bounds.X, (int)Math.Round(bounds.Y + (bounds.Height - tabPage.ImageList.ImageSize.Height) / 2d), imageIndex);
                        TextRenderer.DrawText(e.Graphics, tabPage.Text, this.Font, new Rectangle(bounds.X + tabPage.ImageList.ImageSize.Width + 3, bounds.Y, bounds.Width - tabPage.ImageList.ImageSize.Width, bounds.Height), pen.Color, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
                    }
                    else
                    {
                        TextRenderer.DrawText(e.Graphics, tabPage.Text, this.Font, bounds, pen.Color, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
                    }

                    left += bounds.Width + 24;
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            var tabPage = this.TabPages.OfType<TabPage>().FirstOrDefault(item => this.GetTabPageBounds(item).Contains(e.Location));
            Cursor cursor = tabPage is object ? Cursors.Hand : Cursors.Default;
            if (!this.Cursor.Equals(cursor))
            {
                this.Cursor = cursor;
            }

            if (!Equals(this.mouse_tabPage, tabPage))
            {
                this.mouse_tabPage = tabPage;
                this.Invalidate();
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            this.Cursor = Cursors.Default;
            if (this.mouse_tabPage is object)
            {
                this.mouse_tabPage = null;
                this.Invalidate();
            }
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int @int = 0;
                foreach (TabPage tabPage in this.TabPages)
                {
                    if (this.GetTabPageBounds(tabPage).Contains(e.Location))
                    {
                        // Dim controlAccessibleObject As ControlAccessibleObject = MyBase.AccessibilityObject
                        // If controlAccessibleObject IsNot Nothing Then
                        // controlAccessibleObject.NotifyClients(AccessibleEvents.Focus, int)
                        // End If
                        if (!this.DesignMode)
                        {
                            this.SelectedTab = tabPage;
                        }
                        else
                        {
                            this.designMode_SelectedTab = tabPage;
                            tabPage.BringToFront();
                            tabPage.Visible = true;
                            this.Invalidate();
                        }
                        // Me.Select()
                        continue;
                    }

                    @int += 1;
                }
            }

            base.OnMouseClick(e);
        }

        public Rectangle GetTabPageBounds(TabPage tabPage)
        {
            if (this.dic.ContainsKey(tabPage))
            {
                return this.dic[tabPage];
            }
            else
            {
                return default;
            }
        }

        public void BeginInit()
        {
            this.doubleBuffer = false;
        }

        public void EndInit()
        {
            this.doubleBuffer = true;
            if (this.TabPages.Count > 0 && this.SelectedTab is null)
            {
                this.SelectedTab = this.TabPages[0];
            }
        }

        private void TabControl_ControlRemoved(object sender, ControlEventArgs e)
        {
            if (e.Control is TabPage)
            {
                this.TabPages.Remove((TabPage)e.Control);
            }
        }
    }
}